home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Stuart's Tech Notes / VirtualTemporaryMemory < prev   
Text File  |  1996-06-01  |  5KB  |  116 lines

  1. /*
  2. VirtualTemporaryMemory
  3. ©1996 Stuart Cheshire <cheshire@CS.Stanford.EDU>
  4.  
  5. Sometimes a program can run in a small amount of memory, but can run a lot
  6. faster if it has more memory available. Recently I wrote a program like this
  7. called StUU (ftp://bolo.stanford.edu/Public/Stuart%27s%20tech%20notes/StUU/).
  8.  
  9. StUU is a super-fast UUdecoder. If there is only 1K of free memory, then StUU
  10. can still decode the file correctly by reading 1K at a time from the disk,
  11. but if there is 1MB or 10MB available, or more, then it can decode much
  12. faster by reading larger blocks from the disk.
  13.  
  14. In StUU 1.0 I decided how much memory to use in the obvious way, by calling
  15. TempMaxMem to see how much free temporary memory was available. This worked
  16. fine on my Mac, but on Macs with RAM Doubler or Virtual Memory turned on it
  17. locks up the Mac. The Mac is not crashed -- it is just thrashing the virtual
  18. memory system so badly that it will take hours to finish decoding. One of
  19. those cases where more is less.
  20.  
  21. So, how does a well written program decide how much memory to use?
  22.  
  23. After pondering this problem for a while, here is the solution I have come
  24. up with:
  25.  
  26. If VM (and RAM Doubler) is off, then just use the normal TempMaxMem call,
  27. else:
  28. 1. See how much "holdable" RAM is available. Holdable RAM is the subset of
  29.    Physical RAM that is available for applications to use.
  30. 2. Tentatively decide to use the amount of holdable RAM that is free (not
  31.    currently in use by any other program), or if the amount of free holdable
  32.    RAM is less than 1/16 of the total holdable RAM, tentatively decide to use
  33.    1/16 of the total holdable RAM (it's okay to steal a little back from other
  34.    applications).
  35. 3. If the amount that TempMaxMem told us to use is more than the amount
  36.    we have decided is safe (which is usually the case), we stick to our own
  37.    estimate and ignore TempMaxMem. If TempMaxMem tells us less is available
  38.    (which could happen if the Mac was *really* loaded and there really just
  39.    isn't any memory left) then we use the amount it says.
  40.  
  41. To summarise, the formula for the amount of memory to use is:
  42.  
  43. my_estimate   = max(free holdable RAM, total holdable RAM / 16)
  44. amount_to_use = min(TempMaxMem, my_estimate)
  45.  
  46. If you have an existing program that currently calls "TempMaxMem", just
  47. paste these routines into it and call "sensibleTempMaxMem" instead.
  48.  
  49. NOTE: If your program decides to use all available RAM in this way, it MUST
  50. do it only for a few seconds at most. If you hold the memory for a long time,
  51. the user is going to be VERY annoyed when they find that their 64MB Mac
  52. doesn't have enough free memory left even to launch TeachText. StUU, for
  53. example, typically launches, finishes decoding, and quits in under ten seconds.
  54. This, I think, is acceptable.
  55. */
  56.  
  57. #ifdef __MC68K__
  58.  
  59. // The definition of GetHoldableBytes for 68K code
  60.  
  61. #if !GENERATINGCFM
  62. #pragma parameter __D0 GetHoldableBytes()
  63. #endif
  64. extern pascal Size GetHoldableBytes(void) TWOWORDINLINE(0x70FD, 0xA05C);
  65. #else
  66.  
  67. // The definition of GetHoldableBytes for PPC code
  68.  
  69. static pascal Size GetHoldableBytes(void)
  70.     {
  71.     static short GetHoldableBytes68K[] =
  72.         {
  73.         0x70FD,        // moveq #-3,d0
  74.         0xA05C,        // MemoryDispatch
  75.         0x4E75,        // rts
  76.         };
  77.     enum
  78.         {
  79.         uppGetHoldableBytesProcInfo = kRegisterBased
  80.         | RESULT_SIZE(kFourByteCode) | REGISTER_RESULT_LOCATION(kRegisterD0)
  81.         };
  82.     return(CallUniversalProc((UniversalProcPtr)GetHoldableBytes68K, uppGetHoldableBytesProcInfo));
  83.     }
  84.  
  85. #endif
  86.  
  87. static Size sensibleTempMaxMem(Size *grow)
  88.     {
  89.     Size freemem = TempMaxMem(grow);
  90.     long VMAttr, PhysicalRAM, LogicalRAM;
  91.     
  92.     // if VM on, see if we can revise our estimate of free memory to a more sensible value
  93.     if (TrapAvailable(_Gestalt) &&
  94.         Gestalt(gestaltVMAttr, &VMAttr) == noErr && (VMAttr & (1 << gestaltVMPresent)) &&
  95.         Gestalt(gestaltPhysicalRAMSize, &PhysicalRAM) == noErr &&
  96.         Gestalt(gestaltLogicalRAMSize, &LogicalRAM) == noErr)
  97.         {
  98.         // See how much physical RAM is available
  99.         // If MemoryDispatch is available, use it, else just use
  100.         // a simplistic estimate that half of the physical RAM is holdable
  101.         Size holdable = TrapAvailable(_MemoryDispatch) ? GetHoldableBytes() : PhysicalRAM / 2;
  102.         // See how much memory is in use
  103.         Size usedmem = LogicalRAM - TempFreeMem();
  104.         // See how much physical RAM is free
  105.         Size useable = 0;
  106.         if (holdable > usedmem) useable = holdable - usedmem;
  107.         // If there is very little (or no) physical RAM left, then we'll
  108.         // steal 1/16 of the holdable pages (e.g. 1M on a 16M machine)
  109.         if (useable < holdable/16) useable = holdable/16;
  110.         // If our initial freemem value is more than this amount
  111.         // that we deem sensible to allocate, reduce it 
  112.         if (freemem > useable) freemem = useable;
  113.         }
  114.     return(freemem);
  115.     }
  116.